package com.fjec.market.service.impl;

import com.aliyuncs.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjec.common.Const;
import com.fjec.common.enums.EnumSysCode;
import com.fjec.common.exception.BizException;
import com.fjec.common.protocol.JsonResult;
import com.fjec.common.shiro.AccountInfo;
import com.fjec.common.util.DateUtil;
import com.fjec.common.util.SpecialMapUtil;
import com.fjec.common.view.AnnexBizItem;
import com.fjec.market.entity.BizMarketBusi;
import com.fjec.market.entity.InfoBusiness;
import com.fjec.market.entity.InfoFarmer;
import com.fjec.market.entity.InfoServiceProject;
import com.fjec.market.es.document.BusinessDocument;
import com.fjec.market.es.document.FarmerDocument;
import com.fjec.market.es.document.PurchaseDocument;
import com.fjec.market.es.repository.BusinessRepository;
import com.fjec.market.es.repository.FarmerRepository;
import com.fjec.market.es.repository.PurchaseRepository;
import com.fjec.market.feign.BaseClient;
import com.fjec.market.feign.UserClient;
import com.fjec.market.mapper.InfoBusinessMapper;
import com.fjec.market.rabbitmq.provider.ShopNumProvider;
import com.fjec.market.service.*;
import com.google.common.base.Functions;
import com.google.common.collect.Lists;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 005.商户表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-09-07
 */
@Service
@Transactional
public class InfoBusinessServiceImpl extends ServiceImpl<InfoBusinessMapper, InfoBusiness> implements IInfoBusinessService {

    @Resource
    private InfoBusinessMapper mapper;

    @Resource
    private BusinessRepository businessRepository;

    @Resource
    private IBizMarketBusiService bizMarketBusiService;

    @Resource
    private UserClient userClient;

    @Resource
    private IInfoFarmerService infoFarmerService;

    @Autowired
    private BaseClient baseClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private FarmerRepository farmerRepository;

    @Autowired
    private PurchaseRepository purchaseRepository;

    @Resource
    private ShopNumProvider shopNumProvider;

    @Resource
    private IInfoPersonalService personalService;

    @Resource
    private IInfoServiceProjectService infoServiceProjectService;

    @Override
    public List<InfoBusiness> getBusinessByMarkIdAndBusiType(Integer markCode, int busiType, Page page) {
        return mapper.getBusinessByMarkIdAndBusiType(markCode, busiType, page);
    }

    @Override
    public List<InfoBusiness> getBusinessesByBusinessIdsAndMarkCode(int markCode, List<Long> businessIds, int busiType, Page page) {
        return mapper.getBusinessesByBusinessIdsAndMarkCode(markCode, businessIds, busiType, page);
    }

    @Override
    public Map<String, Object> getBusinessByUserId(Long userId) {
        List<Map<String, Object>> list = mapper.getBusinessWithMarkCodeByUserId(userId);
        if (list.size() == 0) return null;

        Map<String, Object> result = list.get(0);

        List<Integer> markCode = new ArrayList<>();

        if (list.size() > 1) {
            markCode = list.stream().map(r -> MapUtils.getInteger(r, "MarkCode")).collect(Collectors.toList());
        } else {
            markCode.add(MapUtils.getInteger(result, "MarkCode"));
        }

        result = SpecialMapUtil.lowKey(result);

        // del by sz 2020-10-24 for 前台无需此字段 start
//        Object validPeriod = MapUtils.getObject(result, "validPeriod");
//        if (validPeriod != null) {
//            result.put("validPeriod", DateUtil.format(((java.sql.Date) validPeriod).toLocalDate(), "yyyy-MM-dd"));
//        } else {
//            result.put("validPeriod", "");
//        }
//        Object establishDate = MapUtils.getObject(result, "establishDate");
//        if (establishDate != null) {
//            result.put("establishDate", DateUtil.format(((java.sql.Date) establishDate).toLocalDate(), "yyyy-MM-dd"));
//        } else {
//            result.put("establishDate", "");
//        }
//        result.put("validPeriod", DateUtil.format(((java.sql.Date) result.get("validPeriod")).toLocalDate(), "yyyy-MM-dd"));
//        result.put("establishDate", DateUtil.format(((java.sql.Date) result.get("establishDate")).toLocalDate(), "yyyy-MM-dd"));
        // del by sz 2020-10-24 for 前台无需此字段 end
        if (markCode != null)
            result.put("markCode", markCode);
        String shopNum = MapUtils.getString(result, "shopNum");
        String shopNumStr = shopNum.substring(0, 2) + "-" + shopNum.substring(2);
        result.put("shopNum", shopNumStr);

        result.remove("validPeriod");
        result.remove("establishDate");
        return result;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public JsonResult saveBusiness(InfoBusiness business, String markCodes, Long picId, Object verifyCode) {
        if (business.getId() == null) {
            // check verify code
            String cachedVerifyCodeKey = Const.FJEC_SMS_VERIFY_CODE_KEY + business.getPhone();
            Object cachedVerifyCode = redisTemplate.opsForValue().get(cachedVerifyCodeKey);
            if (verifyCode == null || !Objects.equals(cachedVerifyCode, verifyCode)) {
                return JsonResult.failure()
                        .code(EnumSysCode.ERR_3009.getCode())
                        .message(EnumSysCode.ERR_3009.getMsg())
                        .build();
            }
            // check phone exists
            String phone = business.getPhone();
            if (userClient.existsPhone(phone)) {
                return JsonResult.failure()
                        .code(EnumSysCode.ERR_3014.getCode())
                        .message(EnumSysCode.ERR_3014.getMsg())
                        .build();
            }
            // 已经注册过的用户不允许再注册
            if (AccountInfo.getBusiType() != 1)
                return JsonResult.failure()
                        .code(EnumSysCode.ERR_3013.getCode())
                        .message(EnumSysCode.ERR_3013.getMsg())
                        .build();
            // 检查店铺名是否存在
            String name = business.getShopName();
            int exist = this.count(new QueryWrapper<InfoBusiness>().eq("ShopName", name));
            if (exist != 0) {
                return JsonResult.failure()
                        .code(EnumSysCode.ERR_3011.getCode())
                        .message(EnumSysCode.ERR_3011.getMsg())
                        .build();
            }
            // save purchase
            business.setShopNum(0L);
            business.setDepoStatus(0);
            business.setShopStar(0);
            business.setWeight(0);
            business.setAllowPhone(1);
            business.setRegStatus(1);
            business.setCreateTime(DateUtil.nowLdt());
            this.save(business);
            // 商户首次注册时只能属于一个市场
            BizMarketBusi bizMarketBusi = new BizMarketBusi();
            bizMarketBusi.setBusiType(business.getBusiType());
            bizMarketBusi.setMarkCode(Integer.valueOf(markCodes));
            bizMarketBusi.setBusiId(business.getId());
            bizMarketBusi.setPaidRent(0);
            bizMarketBusiService.save(bizMarketBusi);
            // 更新InfoPersonal busiType用于统计
            personalService.updateBusiTypeByUserId(business.getUserId(), business.getBusiType());
            // save to es
            businessRepository.save(new BusinessDocument(business.getId(), AccountInfo.getUserId(), business.getShopName(), business.getBusiType()));
//            String role = "";
//            switch (business.getBusiType()) {
//                case 3:
//                    role = "SortingPlant";
//                    break;
//                case 4:
//                    role = "Material";
//                    break;
//                case 5:
//                    role = "PkgPlant";
//                    break;
//                default:
//            }
//            userClient.saveUserRole(business.getUserId(), role);
            // RPC更新用户信息
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("userId", business.getUserId());
            dataMap.put("phone", phone);
            switch (business.getBusiType()) {
                case 3:
                    dataMap.put("roleCode", "SortingPlant");
                    break;
                case 4:
                    dataMap.put("roleCode", "Material");
                    break;
                case 5:
                    dataMap.put("roleCode", "PkgPlant");
                    break;
                default:
            }
            int result = userClient.updateUserInfoForCreateShop(dataMap);
            if (result == -1) {
                throw new BizException(EnumSysCode.FAILURE.getCode(), EnumSysCode.FAILURE.getMsg());
            } else if (result == 3014) {
                throw new BizException(EnumSysCode.ERR_3014.getCode(), EnumSysCode.ERR_3014.getMsg());
            }
            // 发送MQ创建ShopNum，农资为常亮Const.MARKET_CODE_MATERIAL的值
            if (business.getBusiType() == 4) {
                shopNumProvider.sendShopNumGen(business.getBusiType(), business.getId(), Const.MARKET_CODE_MATERIAL);
            } else {
                shopNumProvider.sendShopNumGen(business.getBusiType(), business.getId(), Integer.valueOf(markCodes));
            }
            // delete verify code from redis
            redisTemplate.delete(cachedVerifyCodeKey);
            return JsonResult.SUCCESS;
        } else {
            business.setRegStatus(2);
            this.updateById(business);
            if (business.getBusiType() == 4) {
                bizMarketBusiService.remove(new QueryWrapper<BizMarketBusi>().eq("BusiId", business.getId()));
                List<BizMarketBusi> bizMarketBusiList = new ArrayList<>();
                Arrays.asList(markCodes.split(",")).forEach(markCode -> {
                    BizMarketBusi bizMarketBusi = new BizMarketBusi();
                    bizMarketBusi.setBusiType(business.getBusiType());
                    bizMarketBusi.setMarkCode(Integer.valueOf(markCode));
                    bizMarketBusi.setBusiId(business.getId());
                    bizMarketBusi.setPaidRent(0);
                    bizMarketBusiList.add(bizMarketBusi);
                });
                bizMarketBusiService.saveBatch(bizMarketBusiList);
            }
            // 店铺头像
            if (picId != null && picId != 0L) {
                List<AnnexBizItem> annexBizItems = new ArrayList<>();
                AnnexBizItem bizItem = new AnnexBizItem();
                bizItem.setAnnexId(Long.valueOf(picId));
                bizItem.setBizId(business.getId());
                bizItem.setBizType(2);
                annexBizItems.add(bizItem);
                baseClient.enableAnnexStatus(annexBizItems);
            }
            return JsonResult.SUCCESS;
        }
    }

    @Override
    public Map<String, Object> getDepoStatus(Long userId) {
        if (userId == null)
            userId = AccountInfo.getUserId();
        Map m = infoFarmerService.getFarmerDepoStatusByUserId(userId);
        if (m != null && m.get("DepoStatus") != null)
            return m;
        m = infoFarmerService.getBusinessDepoStatusByUserId(userId);
        if (m != null && m.get("DepoStatus") != null)
            return m;

        return null;

    }

    @Override
    public JsonResult getDepositInfo() {
        Long userId = AccountInfo.getUserId();
        QueryWrapper<InfoBusiness> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", userId);
        InfoBusiness entity = mapper.selectOne(queryWrapper);
        Map<String, Object> view = new HashMap<>();
        view.put("depoStatus", entity.getDepoStatus());
        view.put("deposit", entity.getDeposit());
        view.put("depoPaymTime", entity.getDepoPaymTime());
        view.put("depoApplyBackTime", entity.getDepoApplyBackTime());
        view.put("depoRefundTime", entity.getDepoRefundTime());
        Integer busiType = AccountInfo.getBusiType();
        String servCode = "depo" + busiType;
        InfoServiceProject serviceProject = infoServiceProjectService.getOne(new QueryWrapper<InfoServiceProject>().eq("ServCode", servCode));
        view.put("amount", serviceProject.getAmount() / 100);
        return JsonResult.success()
                .data(view)
                .build();
    }

    @Override
    public List<Map<String, Object>> getBusinessForShopNumGen(Integer limit, Integer minutes) {
        return mapper.getBusinessForShopNumGen(limit, minutes);
    }

    @Override
    public Page getBusinessesOfAllTypesByConditions(Integer searchBy, String title, Integer busiType, Integer markCode, String startTime, String endTime, Page page) {
        List<Long> ids = new ArrayList<>();
        if (title != null && !title.equals("") && searchBy == 1) {
            if (busiType == 2)
                ids.addAll(farmerRepository.findByShopName(title).stream().map(FarmerDocument::getId).collect(Collectors.toList()));
            else if (busiType == 6)
                ids.addAll(purchaseRepository.findByShortName(title).stream().map(PurchaseDocument::getId).collect(Collectors.toList()));
            else if (busiType == 3 || busiType == 4 || busiType == 5)
                ids.addAll(businessRepository.findByShopNameAndBusiType(title, busiType).stream().map(BusinessDocument::getId).collect(Collectors.toList()));
            else {
                ids.addAll(farmerRepository.findByShopName(title).stream().map(FarmerDocument::getId).collect(Collectors.toList()));
                ids.addAll(purchaseRepository.findByShortName(title).stream().map(PurchaseDocument::getId).collect(Collectors.toList()));
                ids.addAll(businessRepository.findByShopName(title).stream().map(BusinessDocument::getId).collect(Collectors.toList()));
            }
            if (ids.size() == 0)
                return new Page();
        }
        startTime = StringUtils.isEmpty(startTime) ? null : startTime + " 00:00:00";
        endTime = StringUtils.isEmpty(endTime) ? null : endTime + " 23:59:59";
        return mapper.getBusinessesOfAllTypesByConditions(searchBy, title, ids.size() == 0 ? null : ids,
                busiType, markCode, startTime, endTime, page);
    }

    @Override
    public List<Long> getUserIdByBusiNameES(String title) {
        List<Long> result = new ArrayList<>();
        List<FarmerDocument> farmers = farmerRepository.findByShopName(title);
        farmers.forEach(f -> result.add(f.getUserId()));

        List<BusinessDocument> businesses = businessRepository.findByShopName(title);
        businesses.forEach(b -> result.add(b.getUserId()));

        List<PurchaseDocument> purchases = purchaseRepository.findByShortName(title);
        purchases.forEach(p -> result.add(p.getUserId()));

        return result;
    }

    @Override
    public List<Map<String, Object>> getBusiNamesByBusiIdOrUserIds(List<Long> busiIdOrUserIds) {
        return mapper.getBusiNamesByBusiIdOrUserIds(busiIdOrUserIds);
    }

    @Override
    public Long getUserIdByBusiIdBusiType(Long busiId, Integer busiType) {
        switch (busiType) {
            case 2:
                InfoFarmer farmer = infoFarmerService.getById(busiId);
                return farmer.getUserId();
            case 3:
            case 4:
            case 5:
                InfoBusiness business = this.getById(busiId);
                return business.getUserId();
            default:
                return null;
        }
    }

    @Override
    public List<InfoBusiness> getBusinessByShopNumAndMarkCode(int markCode, Long shopNum, int busiType) {
        return mapper.getBusinessByShopNumAndMarkCode(markCode, shopNum, busiType);
    }
}
